package com.wyz.utils.dingtalk.utils;

import com.alibaba.fastjson.JSONObject;
import com.wyz.utils.dingtalk.req.ApprovalTemplateTableRes;
import com.wyz.utils.dingtalk.annotation.FormCells;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wyz
 */
public class DingTalkAnalyzeUtils {
    private DingTalkAnalyzeUtils(){}

    /**
     *  解析
     * @param resList
     * @param cls 解析后转换的实体类class 对象
     * @return 返回解析后实体类
     * @param <T>
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static  <T> T process(List<ApprovalTemplateTableRes> resList, Class<T> cls) throws IllegalAccessException, InstantiationException {
        // 反射创建对象
        T obj = cls.newInstance();
        //反射获取待带有@FormCells 注解的所有字段属性 并将 @FormCells 的值作为key  Field 作为value 转化为map
        Field[] fields = cls.getDeclaredFields();
        Map<String, Field> fieldMap = Arrays.stream(fields).filter(field -> field.isAnnotationPresent(FormCells.class
        )).collect(Collectors.toMap(field -> field.getAnnotation(FormCells.class).name(), Function.identity()));
        // 遍历报文
        for (ApprovalTemplateTableRes res : resList) {
            // 获取钉钉审批表单项的名字
            String name = res.getName()==null ? res.getLabel() : res.getName();
            // 根据名称获取Field
            Field field = fieldMap.get(name);
            if (field == null){
                continue;
            }
            field.setAccessible(true);
            // 获取注解信息
            FormCells annotation = field.getAnnotation(FormCells.class);
            String value = annotation.analyzeValue()?res.getValue():res.getExtValue();
            // 判断字段类型
            if (field.getType().isAssignableFrom(String.class)) {
                // 直接将value 赋值
                field.set(obj,value);
                continue;
            }
            // 字段类型是否为集合
            if(isCollection(field)){
                List<?> target;
                if ("".equals(annotation.targetCollectionName())){
                    //直接转化
                    target = JSONObject.parseArray(value,getTargetClass(field));
                }else{
                    // 获取钉钉审批表单项的值 转化为List  并递归解析获取解析后的列表
                    List<JSONObject> list = JSONObject.parseArray(value ,JSONObject.class);
                    target = list.stream().map(jsonObject -> {
                        String s = jsonObject.getString(annotation.targetCollectionName());
                        List<ApprovalTemplateTableRes> approvalTemplateTableRes = JSONObject.parseArray(s, ApprovalTemplateTableRes.class);
                        try {
                            return process(approvalTemplateTableRes, getTargetClass(field));
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        } catch (InstantiationException e) {
                            throw new RuntimeException(e);
                        }
                    }).collect(Collectors.toList());
                }

                // 反射赋值
                field.set(obj,target);
                continue;
            }
            //todo 目前还没有遇到需要转化为对象的数据结构 暂时这样处理
            if (annotation.isArray()) {
                JSONObject jsonObject = JSONObject.parseObject(res.getValue(),JSONObject.class);
                //如果是对象
                List<ApprovalTemplateTableRes> list = JSONObject.parseArray(jsonObject.toString(),ApprovalTemplateTableRes.class);
                // 递归解析
                Object process = process(list, getTargetClass(field));
                // 将解析后的对象 进行反射赋值
                field.set(obj,process);
            } else{
                Object object = JSONObject.parseObject(res.getValue(),getTargetClass(field));
                // 将解析后的对象 进行反射赋值
                field.set(obj,object);
            }

        }
        return obj;

    }


    /**
     *  获取Field 数据类型的class对象，如果是集合则返回集合范型的class 对象
     *  比如：
     *      List<T> 则返回 T.class
     *      String 则返回 String.class
     * @param field
     * @return
     */
    public static Class<?> getTargetClass(Field field){
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType){
            for (Type actualTypeArgument : ((ParameterizedType) type).getActualTypeArguments()) {
                if (actualTypeArgument instanceof Class){
                    return (Class) actualTypeArgument;
                }
            }
        }
        return field.getType();

    }

    /**
     *  判断Field 是否是集合
     * @param field
     * @return
     */
    public static boolean isCollection(Field field) {
        return   field.getType().isAssignableFrom(List.class)||
                field.getType().isAssignableFrom(Set.class)||
                field.getType().isAssignableFrom(Collection.class);

    }

}
